﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using NEmu;

namespace Super64.Core.Memory.Rom
{
    [Serializable]
    public sealed class CartRom
    {
        private CartHeader m_Header;
        private Stream m_Rom;

        public CartRom(Stream inStream)
        {
            m_Rom = PrepareRawStream(inStream);
            m_Header = Tools.FillStruct<CartHeader>(inStream);
        }

        private Stream PrepareRawStream(Stream inStream)
        {
            switch (RomUtility.DetectRomFormat(inStream))
            {
                case RomFormat.V64: return RomUtility.ByteSwapStream(inStream);
                case RomFormat.N64: return RomUtility.WordSwapStream(inStream);
                case RomFormat.Z64: break;
                default: break;
            }

            return inStream;
        }

        public Stream GenerateBootCodeStream()
        {
            return new MemoryStream(m_Header.BootCode, false);
        }

        public string GameName
        {
            get { return m_Header.ImageName; }
        }

        public ManufacturerName ManufacturerName
        {
            get
            {
                foreach (ManufacturerName name in Enum.GetValues(typeof(ManufacturerName)))
                {
                    object[] attributes = Tools.GetEnumAttributes<ManufacturerName>(name, typeof(ManufacturerCode));

                    if (attributes.Length > 0)
                    {
                        ManufacturerCode code = new ManufacturerCode(((ManufacturerCode)attributes[0]).Code);

                        if (m_Header.MalfactureID.Equals(code))
                        {
                            return name;
                        }
                    }
                }

                return ManufacturerName.Unknown;
            }
        }

        public Language GameLanguage
        {
            get
            {
                foreach (Language lang in Enum.GetValues(typeof(Language)))
                {
                    object[] attributes = Tools.GetEnumAttributes<Language>(lang, typeof(LanguageCode));

                    if (attributes.Length > 0)
                    {
                        LanguageCode code = new LanguageCode(((LanguageCode)attributes[0]).Code);

                        if (m_Header.CountryCode.Equals(code))
                        {
                            return lang;
                        }
                    }
                }

                return Language.Unknown;
            }
        }

        public string CartID
        {
            get { return m_Header.CartID; }
        }

        public Stream RawStream
        {
            get { return m_Rom; }
        }

        public CartHeader Header
        {
            get { return m_Header; }
        }

        public uint ProgramCounter
        {
            get { return m_Header.ProgramCounter; }
        }

        public uint CRC1
        {
            get { return m_Header.CRC1; }
        }

        public uint CRC2
        {
            get { return m_Header.CRC2; }
        }
    }
}
